/*
 * Copyright 2011 J. Auer, J. Andert, F.-J. Jendrusch, U. Celebi
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package de.fuberlin.replication.application.android.communication.bluetooth;

import java.io.IOException;
import java.util.concurrent.Semaphore;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import de.fuberlin.replication.R;
import de.fuberlin.replication.application.android.communication.CommunicationHelperAbstract;
import de.fuberlin.replication.communication.CommunicationAlreadyEstablishedException;
import de.fuberlin.replication.communication.CommunicationNotYetEstablishedException;
import de.fuberlin.replication.communication.bluetooth.BluetoothNotEnabledException;
import de.fuberlin.replication.communication.bluetooth.BluetoothNotSupportedException;
import de.fuberlin.replication.communication.bluetooth.android.BluetoothCommunication;

/**
 * Android-specific Bluetooth communication helper.
 */
public class BluetoothCommunicationHelper extends CommunicationHelperAbstract {
	private static final String TAG = "BluetoothCommunicationHelper";

	/** Enable Bluetooth request code. */
	public static final int REQUEST_ENABLE_BLUETOOTH = 1;

	/** Select device request code. */
	public static final int REQUEST_SELECT_DEVICE = 2;

	/** Enable Bluetooth request wait semaphore. */
	Semaphore wait;

	/** Bluetooth adapter (default). */
	BluetoothAdapter adapter;

	/** Bluetooth communication. */
	BluetoothCommunication communication;

	/**
	 * @see CommunicationHelperAbstract#CommunicationHelperAbstract()
	 */
	public BluetoothCommunicationHelper() {
		super();
	}

	@Override
	public BluetoothCommunication getCommunication() {
		if (communication == null)
			throw new IllegalStateException("Synchronization not yet started");

		return communication;
	}

	@Override
	protected void listen() throws IOException {
		communication.listen();
	}

	@Override
	protected void connect() {
		Intent intent = new Intent(getActivity(), BluetoothDeviceListActivity.class);
		getActivity().startActivityForResult(intent, REQUEST_SELECT_DEVICE);
	}

	@Override
	protected void waitEstablished() {
		communication.waitEstablished();
	}

	@Override
	protected void close() {
		if (communication != null)
			communication.close();
	}

	@Override
	public void onSynchronizationStart() {
		syncRunOnUiThread(new Runnable() {
			@Override
			public void run() {
				adapter = BluetoothAdapter.getDefaultAdapter();
			}
		});

		if (adapter == null) {
			getUIHandler().obtainMessage(UICallback.MESSAGE_TOAST, R.string.toast_bluetooth_not_supported,
					Toast.LENGTH_SHORT).sendToTarget();

			throw new BluetoothNotSupportedException();
		} else if (!adapter.isEnabled()) {
			wait = new Semaphore(0);

			Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
			getActivity().startActivityForResult(enableIntent, REQUEST_ENABLE_BLUETOOTH);

			wait.acquireUninterruptibly();
			wait = null;

			if (!adapter.isEnabled()) {
				getUIHandler().obtainMessage(UICallback.MESSAGE_TOAST, R.string.toast_bluetooth_not_enabled,
						Toast.LENGTH_SHORT).sendToTarget();

				throw new BluetoothNotEnabledException();
			}
		}

		syncRunOnUiThread(new Runnable() {
			@Override
			public void run() {
				communication = new BluetoothCommunication();
			}
		});

		super.onSynchronizationStart();
	}

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		switch (requestCode) {
			case REQUEST_ENABLE_BLUETOOTH:
				wait.release();

				break;
			case REQUEST_SELECT_DEVICE:
				if (resultCode == Activity.RESULT_OK) {
					ConnectTask task = new BluetoothConnectTask();
					task.execute(data.getExtras().getString(BluetoothDeviceListActivity.EXTRA_DEVICE_ADDRESS));
				} else
					getUIHandler().obtainMessage(UICallback.MESSAGE_DIALOG_SHOW, DIALOG_INITIALIZING, 0).sendToTarget();

				break;
			default:
				super.onActivityResult(requestCode, resultCode, data);

				break;
		}
	}

	private class BluetoothConnectTask extends ConnectTask {
		public BluetoothConnectTask() {
			super();
		}

		@Override
		protected Boolean doInBackground(String... params) {
			boolean result = false;

			for (int i = 0; i < params.length; i++)
				try {
					communication.connect(params[i], false);

					result = true;

					break;
				} catch (CommunicationAlreadyEstablishedException e) {
					break;
				} catch (CommunicationNotYetEstablishedException e) {
					continue;
				} catch (IOException e) {
					Log.e(TAG, "connect() failed", e);
				}

			return Boolean.valueOf(result);
		}
	}
}